﻿Imports MostRecentlyUsed.MRUItems
Imports System.Text
Imports Microsoft.Win32

Namespace Controls
    Public Class ctlOpenRecentOffice
        Private Const INDEX_PRODUCT As Integer = 0
        Private Const INDEX_TYPE As Integer = 1
        Private Const INDEX_VERSION As Integer = 2

        Private m_bAscending As Boolean = True
        Private m_iCurrentColumn As Integer
        Private ReadOnly m_oIconCache As New Dictionary(Of String, Integer)()

        Enum ItemListColumnPosition
            Number
            ItemName
            ItemPath
        End Enum

        Enum RecentItemType
            Files
            Places
        End Enum

        Private Sub ctlOpenRecentOffice_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Try
                Dim szDefault As String = My.Settings.OfficeVersion

                If (String.IsNullOrWhiteSpace(szDefault)) Then szDefault = String.Empty

                Dim aszParts As String() = szDefault.Split("|".ToCharArray(), 3, StringSplitOptions.RemoveEmptyEntries)

                If (aszParts.Length > 0) Then
                    If (aszParts.Length > 2) Then
                        ' This means we have product, type and version
                        For iPos = 0 To cbVersion.Items.Count
                            If (String.Compare(aszParts(INDEX_VERSION), Convert.ToString(cbVersion.Items(iPos))) = 0) Then
                                cbVersion.SelectedItem = cbOfficeProduct.Items(iPos)
                                Exit For
                            End If
                        Next
                    End If
                    If (aszParts.Length > 1) Then
                        ' This means we have product and type
                        If (String.Compare("file", aszParts(INDEX_TYPE), True) = 0) Then
                            optFiles.Checked = True
                        Else
                            optPlaces.Checked = True
                        End If
                    End If

                    For iPos = 0 To cbOfficeProduct.Items.Count
                        If (String.Compare(aszParts(INDEX_PRODUCT), Convert.ToString(cbOfficeProduct.Items(iPos))) = 0) Then
                            cbOfficeProduct.SelectedItem = cbOfficeProduct.Items(iPos)
                            Exit For
                        End If
                    Next
                End If

                Show()

                If (cbOfficeProduct.SelectedIndex < 0) Then cbOfficeProduct.SelectedIndex = 0
                If (cbVersion.SelectedIndex < 0) Then cbVersion.SelectedIndex = 0

            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Loading Recent Office Control")
            End Try
        End Sub

        Private Sub pbDefault_Click(sender As Object, e As EventArgs) Handles pbDefault.Click
            Try
                Dim szType As String = If(optFiles.Checked, "file", "places")
                My.Settings.OfficeVersion = String.Join("|", cbOfficeProduct.Text, szType, cbVersion.Text)
                My.Settings.Save()
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Setting Default Office Product")
            End Try
        End Sub

        Private Sub cbVersion_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbVersion.SelectedIndexChanged
            Dim bBindList As Boolean = True
            Try
                If (cbVersion.SelectedItem.ToString() = "2007") Then
                    optPlaces.Enabled = False
                    If (optPlaces.Checked) Then
                        optFiles.Checked = True
                        ' Toggling the checked property will cause a rebind, so do not do it again
                        bBindList = False
                    End If
                Else
                    ' The places did not exist until 2010
                    optPlaces.Enabled = True
                End If

                If bBindList Then BindList()
            Catch
            End Try
        End Sub

        Private Sub cbOfficeProduct_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbOfficeProduct.SelectedIndexChanged
            Try
                BindList()
            Catch
            End Try
        End Sub

        Private Sub optFiles_CheckedChanged(sender As Object, e As EventArgs) Handles optFiles.CheckedChanged
            Try
                BindList()
            Catch
            End Try
        End Sub

        Private Sub optPlaces_CheckedChanged(sender As Object, e As EventArgs) Handles optPlaces.CheckedChanged
            Try
                BindList()
            Catch
            End Try
        End Sub

        Private Sub txtFilter_TextChanged(sender As Object, e As EventArgs) Handles txtFilter.TextChanged
            Try
                Dim szFilter As String = txtFilter.Text.Trim()
                If (lstItems.Items.Count > 0) And (szFilter.Length >= 3) Then
                    lstItems.SelectedItems.Clear()
                    For Each oItem As ListViewItem In lstItems.Items
                        If (oItem.SubItems(2).Text.IndexOf(szFilter, StringComparison.OrdinalIgnoreCase) >= 0) Then
                            oItem.ForeColor = Color.Red
                            oItem.Checked = True
                        Else
                            oItem.Checked = False
                        End If
                    Next
                ElseIf (txtFilter.Text.Length = 0) Then
                    For Each oItem As ListViewItem In lstItems.Items
                        oItem.Checked = False
                    Next
                End If
            Catch
            End Try
        End Sub

        Private Sub txtFilter_KeyUp(sender As Object, e As KeyEventArgs) Handles txtFilter.KeyUp
            Try
                If (e.KeyCode = Keys.Escape) Then
                    txtFilter.Clear()
                End If
            Catch
            End Try
        End Sub

        Private Sub pbCancel_Click(sender As Object, e As EventArgs) Handles pbCancel.Click
            Try
                Dim oParent As frmMain = ParentForm
                oParent.Close()
            Catch
            End Try
        End Sub

        Private Sub lstItems_ColumnClick(sender As Object, e As ColumnClickEventArgs) Handles lstItems.ColumnClick
            Try
                If e.Column = m_iCurrentColumn Then
                    m_bAscending = Not m_bAscending
                Else
                    m_bAscending = True
                End If

                ' Set the ListViewItemSorter property to a new ListViewItemComparer object.
                Dim eCompareType As ListViewItemComparer.CompareType
                If e.Column = CInt(ItemListColumnPosition.Number) Then
                    eCompareType = ListViewItemComparer.CompareType.Int
                Else
                    eCompareType = ListViewItemComparer.CompareType.[String]
                End If
                lstItems.ListViewItemSorter = New ListViewItemComparer(e.Column, m_bAscending, eCompareType)
                ' Call the sort method to manually sort.
                lstItems.Sort()

                m_iCurrentColumn = e.Column
            Catch
            End Try
        End Sub

        Private Sub lstItems_DoubleClick(sender As Object, e As EventArgs) Handles lstItems.DoubleClick
            Try
                pbOpen_Click(sender, e)
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Opening Selected Items(s)")
            End Try
        End Sub

        Private Sub lstItems_ItemChecked(sender As Object, e As ItemCheckedEventArgs) Handles lstItems.ItemChecked
            Try
                If (e.Item.Checked = True) Then
                    e.Item.ForeColor = Color.Red
                Else
                    e.Item.ForeColor = lstItems.ForeColor
                End If
            Catch
            End Try
        End Sub

        Private Sub pbOpen_Click(sender As Object, e As EventArgs) Handles pbOpen.Click
            Try
                ' TODO: 
                'OpenProjectsToolStripMenuItem_Click(sender, e)
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Opening Selected Items(s)")
            End Try
        End Sub

        Private Sub BindList()
            Try
                ' The form is not fully loaded yet, so we cannot bind
                If (cbVersion.SelectedIndex < 0) Then Return
                If (cbOfficeProduct.SelectedIndex < 0) Then Return

                lstItems.Items.Clear()
                m_oIconCache.Clear()
                m_oIconImageList.Images.Clear()

                Dim eRecentItemType As RecentItemType = RecentItemType.Files
                If (optPlaces.Checked) Then eRecentItemType = RecentItemType.Places

                Dim colMRUPaths As List(Of String) = If(eRecentItemType = RecentItemType.Places, GetPlacesMRUPaths(), GetFilesMRUPaths())

                For Each szMRUPath As String In colMRUPaths
                    Dim oMRUList As List(Of OfficeMRUItem) = Helper.GetMRUList(Of OfficeMRUItem)(Helper.ProjectType.Office, eRecentItemType, szMRUPath,
                                                                                                                cbVersion.Text.Trim().ToUpper())
                    Dim iPos As Integer = 1
                    For Each oMRUItem As OfficeMRUItem In oMRUList
                        Try
                            Dim szName As String
                            Dim bUri As Boolean

                            Try
                                Dim oInfo As New FileInfo(oMRUItem.Path)
                                szName = oInfo.Name
                                If (szName.Length = 0) AndAlso (oInfo.Directory.Name.Length > 0) Then szName = oInfo.Directory.Name
                                bUri = False
                            Catch oExp As Exception
                                Dim oUri As New Uri(oMRUItem.Path)
                                If (Not String.IsNullOrWhiteSpace(oUri.LocalPath)) Then
                                    Dim iIndex As Integer = oUri.LocalPath.LastIndexOf("/"c) + 1
                                    If (iIndex > 0) Then
                                        szName = oUri.LocalPath.Substring(iIndex)
                                    Else
                                        szName = oUri.LocalPath
                                    End If
                                Else
                                    szName = oUri.AbsolutePath
                                End If
                                bUri = True
                            End Try

                            'New
                            Dim oNumberItem As New ListViewItem()
                            oNumberItem.Text = iPos.ToString()
                            oNumberItem.Tag = oMRUItem.Name
                            oNumberItem.ImageIndex = GetIconIndex(oMRUItem.Path, bUri)
                            oNumberItem.StateImageIndex = oNumberItem.ImageIndex
                            Dim oProject As New ListViewItem.ListViewSubItem(oNumberItem, szName)
                            oProject.Tag = oMRUItem.Name
                            Dim oPath As New ListViewItem.ListViewSubItem(oNumberItem, oMRUItem.Path)
                            oNumberItem.SubItems.Add(oProject)
                            oNumberItem.SubItems.Add(oPath)
                            lstItems.Items.Add(oNumberItem)

                            iPos += 1
                            'don't throw any exceptions
                        Catch oExp As Exception
                            If (Debugger.IsAttached) Then
                                Helper.DisplayException(oExp, Me, "Error Binding List")
                            End If
                        End Try
                    Next
                Next

                If lstItems.Items.Count = 0 Then
                    lstItems.SmallImageList = Nothing

                    Dim oListItem As New ListViewItem()
                    oListItem.Text = String.Format("You have no recent {0}s.", eRecentItemType)
                    oListItem.SubItems.Add(String.Empty)
                    lstItems.Items.Add(oListItem)
                Else
                    lstItems.SmallImageList = m_oIconImageList
                End If
            Catch oExp As Exception
                If (Debugger.IsAttached) Then
                    Helper.DisplayException(oExp, Me, "Error Binding List")
                End If
            Finally
                lstItems.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent)
                If lstItems.Items.Count > 0 Then
                    lstItems.Items(0).Selected = True
                End If
                lstItems.Focus()
            End Try
        End Sub

        Private Function GetIconIndex(ByVal path As String, ByVal isUri As Boolean) As Integer
            Dim iNum As Integer
            Dim szExtension As String = If(isUri, ".url", New FileInfo(path).Extension).ToLower()
            If m_oIconCache.ContainsKey(szExtension) Then
                Return m_oIconCache(szExtension)
            End If
            If (Not isUri) Then
                AddPathIcon(path)
            Else
                AddExtensionIcon(szExtension)
            End If
            iNum = m_oIconImageList.Images.Count - 1
            m_oIconCache.Add(szExtension, iNum)
            Return iNum
        End Function

        Private Sub AddExtensionIcon(ByVal fileExtension As String)
            Try
                Dim oAssociatedIcon As Icon = Nothing
                Try
                    oAssociatedIcon = Interop.IconFromExtension(fileExtension, IconSize.Small)
                Catch
                End Try
                If oAssociatedIcon IsNot Nothing Then
                    Dim oImage As Bitmap = oAssociatedIcon.ToBitmap()
                    Dim oBitmap2 As New Bitmap(&H12, &H10)
                    Graphics.FromImage(oBitmap2).DrawImageUnscaled(oImage, New Point(2, 0))
                    m_oIconImageList.Images.Add(oBitmap2)
                End If
            Catch
            End Try
        End Sub

        Private Sub AddPathIcon(ByVal filePath As String)
            Try
                Dim oAssociatedIcon As Icon = Nothing
                Try
                    oAssociatedIcon = Interop.GetAssociatedIcon(filePath)
                Catch
                End Try
                If oAssociatedIcon IsNot Nothing Then
                    Dim oImage As Bitmap = oAssociatedIcon.ToBitmap()
                    Dim oBitmap2 As New Bitmap(&H12, &H10)
                    Graphics.FromImage(oBitmap2).DrawImageUnscaled(oImage, New Point(2, 0))
                    m_oIconImageList.Images.Add(oBitmap2)
                End If
            Catch
            End Try
        End Sub

        Private Function GetOfficeProduct() As String
            Select Case cbOfficeProduct.Text.Trim().ToUpper()
                Case "WORD"
                    Return "Word"
                Case "EXCEL"
                    Return "Excel"
                Case Else
                    Throw New ApplicationException(String.Format("Unmapped Office product found: {0}", cbVersion.Text))
            End Select
        End Function

        Private Function GetPlacesMRUPaths() As List(Of String)
            Dim colPaths As List(Of String) = GetOfficeUserRoots()

            For iIndex As Integer = 0 To colPaths.Count - 1
                colPaths(iIndex) = String.Format("{0}\Place MRU", colPaths(iIndex))
            Next

            Return colPaths
        End Function

        Private Function GetFilesMRUPaths() As List(Of String)
            Dim colPaths As List(Of String) = GetOfficeUserRoots()

            For iIndex As Integer = 0 To colPaths.Count - 1
                colPaths(iIndex) = String.Format("{0}\File MRU", colPaths(iIndex))
            Next

            Return colPaths
        End Function

        Private Function GetOfficeUserRoots() As List(Of String)
            Dim colUserRoots As List(Of String) = New List(Of String)()

            Dim szOfficeVersion As String = GetOfficeVersion()
            Dim dOfficeVersion As Decimal = Convert.ToDecimal(szOfficeVersion)

            If dOfficeVersion < 15D Then
                ' Office 2010 or older
                colUserRoots.Add(String.Format("Software\Microsoft\Office\{0}\{1}", szOfficeVersion, GetOfficeProduct()))
                Return colUserRoots
            End If

            ' Office 2013 or newer
            Dim szUserKey As String = String.Format("Software\Microsoft\Office\{0}\{1}\User MRU", szOfficeVersion, GetOfficeProduct())

            Dim oRegKey As RegistryKey = Nothing
            Try
                oRegKey = Registry.CurrentUser.OpenSubKey(szUserKey)

                If (oRegKey IsNot Nothing) Then
                    Dim aszKeyNames As String() = oRegKey.GetSubKeyNames()
                    For Each szName As String In aszKeyNames
                        colUserRoots.Add(szUserKey & "\" & szName)
                    Next
                End If
            Finally
                If oRegKey IsNot Nothing Then
                    oRegKey.Close()
                End If
            End Try

            Return colUserRoots
        End Function

        Private Function GetOfficeVersion() As String
            Dim szVersion As String
            Select Case cbVersion.Text.Trim().ToUpper()
                Case "2007"
                    szVersion = "12.0"
                    Exit Select
                Case "2010"
                    szVersion = "14.0"
                    Exit Select
                Case "2013"
                    szVersion = "15.0"
                    Exit Select
                Case Else
                    Throw New ApplicationException(String.Format("Unmapped Office version found: {0}", cbVersion.Text))
            End Select
            Return szVersion
        End Function

        Private Sub ContextMenuStripItems_Opening(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles ContextMenuStripItems.Opening
            Try
                Dim oParent As frmMain = ParentForm
                If (Not oParent.IsOpenRecentOfficeItemsTabSelected) Or (lstItems.SelectedItems.Count = 0) Then
                    e.Cancel = True
                    Exit Sub
                End If

                OpenItemsToolStripMenuItem.Visible = optFiles.Checked
                copyToFileNameWithoutExtentionToolStripMenuItem.Visible = optFiles.Checked
                copyToFilePathNameToolStripMenuItem.Visible = optFiles.Checked
                getLatestVersionOpenItemsToolStripMenuItem.Visible = optFiles.Checked

                If (optFiles.Checked) Then
                    openContainingDirectoryToolStripMenuItem.Text = "Open Containing Directory"
                    copyToFileNameToolStripMenuItem.Text = "File Name"
                    getLatestVersionOpenContainingDirectoryToolStripMenuItem1.Text = "Open Containing Directory"
                Else
                    openContainingDirectoryToolStripMenuItem.Text = "Open Directory"
                    copyToFileNameToolStripMenuItem.Text = "Folder Name"
                    getLatestVersionOpenContainingDirectoryToolStripMenuItem1.Text = "Open Directory"
                End If

                If (lstItems.SelectedItems.Count <> 1) Then
                    Exit Sub
                End If
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception opening context menu")
            End Try
        End Sub

        Private Sub OpenContainingDirectories()
            For Each oItem As ListViewItem In lstItems.SelectedItems
                Dim oInfo As New FileInfo(oItem.SubItems(ItemListColumnPosition.ItemPath).Text)
                Helper.OpenDirectory(oInfo.Directory.FullName)
            Next
        End Sub

        Private Sub OpenItems()
            For Each oItem As ListViewItem In lstItems.SelectedItems
                Dim szItem As String = oItem.SubItems(ItemListColumnPosition.ItemPath).Text
                Helper.OpenFile(szItem)
            Next
        End Sub

        Private Sub OpenItemsToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OpenItemsToolStripMenuItem.Click
            Try
                Dim oParent As frmMain = ParentForm
                If (oParent.IsOpenRecentOfficeItemsTabSelected And (lstItems.SelectedItems.Count > 0)) Then
                    OpenItems()

                    oParent.CloseIfNoShift()
                End If
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Opening Selected Project(s)")
            End Try
        End Sub

        Private Sub openChildFileToolStripMenuItem_MouseDown(sender As Object, e As MouseEventArgs)
            Try
                Dim oParent As frmMain = ParentForm

                If (Not oParent.IsOpenRecentOfficeItemsTabSelected) Or (lstItems.SelectedItems.Count <> 1) Then Exit Sub

                Dim oFileSenderMenuItem As ToolStripMenuItem = TryCast(sender, ToolStripMenuItem)
                If oFileSenderMenuItem IsNot Nothing Then
                    Dim szTag As String = oFileSenderMenuItem.Tag.ToString()
                    If e.Button = MouseButtons.Left Then
                        If File.Exists(szTag) Then
                            Using oProcess As New Process()
                                oProcess.StartInfo = New ProcessStartInfo(My.Settings.TextEditorPath)
                                oProcess.StartInfo.Arguments = szTag
                                oProcess.Start()
                                oParent.CloseIfNoShift()
                            End Using
                        Else
                            oFileSenderMenuItem.DropDownItems(0).Visible = True
                        End If
                    ElseIf e.Button = MouseButtons.Right Then
                        If Directory.Exists(szTag) Then
                            Using oProcess As New Process()
                                oProcess.StartInfo = New ProcessStartInfo(szTag)
                                oProcess.Start()
                                oParent.CloseIfNoShift()
                            End Using
                        End If
                    End If
                End If
            Catch
            End Try
        End Sub

        Private Sub openContainingDirectoryToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles openContainingDirectoryToolStripMenuItem.Click
            Try
                Dim oParent As frmMain = ParentForm
                If (oParent.IsOpenRecentOfficeItemsTabSelected And (lstItems.SelectedItems.Count > 0)) Then
                    OpenContainingDirectories()
                    oParent.CloseIfNoShift()
                End If
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Opening Containing Directory")
            End Try
        End Sub

        Private Sub CopyToClipboard(sender As Object, e As EventArgs) _
            Handles copyToFileNameToolStripMenuItem.Click, copyToFilePathToolStripMenuItem.Click, copyToFilePathNameToolStripMenuItem.Click,
                    copyToFileNameWithoutExtentionToolStripMenuItem.Click
            Try
                Dim oParent As frmMain = ParentForm
                If oParent.IsOpenRecentOfficeItemsTabSelected AndAlso (lstItems.SelectedItems.Count > 0) Then
                    Dim oTextSB As New StringBuilder()
                    For Each oItem As ListViewItem In lstItems.SelectedItems
                        Dim szItem As String = oItem.SubItems(CInt(ItemListColumnPosition.ItemPath)).Text

                        If copyToFileNameToolStripMenuItem.Equals(sender) Then
                            If (optFiles.Checked) Then
                                oTextSB.AppendLine(MRUFiles.GetFileInfo(szItem, MRUFileInfo.FileNameExtension))
                            Else
                                oTextSB.AppendLine(New DirectoryInfo(szItem).Name)
                            End If
                        ElseIf copyToFileNameWithoutExtentionToolStripMenuItem.Equals(sender) Then
                            oTextSB.AppendLine(MRUFiles.GetFileInfo(szItem, MRUFileInfo.FileName))
                        ElseIf copyToFilePathNameToolStripMenuItem.Equals(sender) Then
                            oTextSB.AppendLine(szItem)
                        ElseIf copyToFilePathToolStripMenuItem.Equals(sender) Then
                            oTextSB.AppendLine(MRUFiles.GetFileInfo(szItem, MRUFileInfo.Path))
                        End If
                    Next

                    If oTextSB.Length > 0 Then
                        Clipboard.SetText(oTextSB.ToString())
                    End If
                End If
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Copying Data To Clipboard")
            End Try
        End Sub

        Private Sub getLatestVersionOpenItemsToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles getLatestVersionOpenItemsToolStripMenuItem.Click
            Try
                Dim oParent As frmMain = ParentForm
                If oParent.IsOpenRecentOfficeItemsTabSelected AndAlso (lstItems.SelectedItems.Count > 0) Then
                    GetLatestVersions()
                    OpenItems()
                    oParent.CloseIfNoShift()
                End If
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Getting Latest Version")
            End Try
        End Sub

        Private Sub getLatestVersionOpenContainingDirectoryToolStripMenuItem1_Click(sender As Object, e As EventArgs) _
            Handles getLatestVersionOpenContainingDirectoryToolStripMenuItem1.Click
            Try
                Dim oParent As frmMain = ParentForm
                If oParent.IsOpenRecentOfficeItemsTabSelected AndAlso (lstItems.SelectedItems.Count > 0) Then
                    GetLatestVersions()
                    OpenContainingDirectories()
                    oParent.CloseIfNoShift()
                End If

            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Getting Latest Version")
            End Try
        End Sub

        Private Sub GetLatestVersions()
            For Each oItem As ListViewItem In lstItems.SelectedItems
                Dim oInfo As New FileInfo(oItem.SubItems(CInt(ItemListColumnPosition.ItemPath)).Text)
                Dim szDirectory As String = oInfo.Directory.FullName
                If (optPlaces.Checked) Then
                    Helper.GetLastestFromSourceControlDirectory(szDirectory, String.Empty)
                Else
                    Helper.GetLastestFromSourceControlDirectory(szDirectory, oInfo.Name)
                End If
            Next
        End Sub

        Private Sub clearItemsFromListToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles clearItemsFromListToolStripMenuItem.Click
            Try
                'Dim szMRUPath As String = If(GetRecentType() = Helper.RecentType.Project, GetProjectMRUPath(), GetFileMRUPath())
                'ClearCheckedKeys(cbVSVersions.Text.Trim().ToUpper(), szMRUPath, lstItems)
                'cbVSVersions_SelectedIndexChanged(sender, Nothing)
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Setting Default VS Version")
            End Try
        End Sub
    End Class
End Namespace
